import { BaseService } from "@cool-midway/core";
import { Inject, Provide } from "@midwayjs/core";
import { InjectEntityModel } from "@midwayjs/typeorm";
import { In, Repository, SelectQueryBuilder } from "typeorm";
import { CommentInfoEntity, RelatedType } from "../../comment/entity/info";
import { ProviderCommentListDTO } from "../dto/comment";
import { UserInfoEntity } from "../../user/entity/info";
import { ProviderProfileEntity } from "../entity/profile";

type ScoreDimension = {
    label: string;
    averageScore: number;
};

type CommentWithRelation = CommentInfoEntity & {
    user: UserInfoEntity | null;
    relatedEntity: ProviderProfileEntity | null;
};

type CommentListResult = {
    list: CommentWithRelation[];
    pagination: {
        page: number;
        size: number;
        total: number;
    };
};

@Provide()
export class ProviderCommentService extends BaseService {

    @InjectEntityModel(CommentInfoEntity)
    commentInfoModel: Repository<CommentInfoEntity>;

    @InjectEntityModel(UserInfoEntity)
    userInfoModel: Repository<UserInfoEntity>;

    @InjectEntityModel(ProviderProfileEntity)
    providerProfileModel: Repository<ProviderProfileEntity>;

    /**
     * 获取服务人员综合评分与评论列表
     * @param dto
     */
    async overview(dto: ProviderCommentListDTO) {
        const summary = await this.summary(dto.providerId);
        const { list, pagination } = await this.list(dto);
        return {
            summary,
            list,
            pagination,
        };
    }

    /**
     * 综合评分概览
     * @param providerId
     */
    async summary(providerId: number) {
        const stats = await this.commentInfoModel.createQueryBuilder('comment')
            .select('COUNT(comment.id)', 'total')
            .addSelect('COALESCE(AVG(comment.averageScore), 0)', 'avg')
            .where('comment.relatedType = :relatedType', { relatedType: RelatedType.PROVIDER })
            .andWhere('comment.relatedId = :providerId', { providerId })
            .getRawOne();

        const total = Number(stats?.total || 0);
        const averageScore = total ? Number(Number(stats?.avg || 0).toFixed(1)) : 0;

        const latest = await this.commentInfoModel.createQueryBuilder('comment')
            .select('comment.createTime', 'createTime')
            .where('comment.relatedType = :relatedType', { relatedType: RelatedType.PROVIDER })
            .andWhere('comment.relatedId = :providerId', { providerId })
            .orderBy('comment.createTime', 'DESC')
            .limit(1)
            .getRawOne();

        const scoreDimensions = await this.dimensionScore(providerId);
        await this.providerProfileModel.update(providerId, { comprehensiveScore: averageScore });
        return {
            total,
            averageScore,
            latestCommentTime: latest?.createTime || null,
            scoreDimensions,
        };
    }

    /**
     * 评论列表
     * @param dto
     */
    async list(dto: ProviderCommentListDTO): Promise<CommentListResult> {
        const { providerId, page = 1, size = 10 } = dto;
        const find = this.queryBuilder(providerId);
        const [list, total] = await find
            .skip((page - 1) * size)
            .take(size)
            .getManyAndCount();
        const enrichedList = await this.attachCommentDetails(list);
        return {
            list: enrichedList,
            pagination: {
                page,
                size,
                total,
            },
        };
    }

    /**
     * 评分维度均值
     * @param providerId
     */
    private async dimensionScore(providerId: number): Promise<ScoreDimension[]> {
        const rows = await this.commentInfoModel.createQueryBuilder('comment')
            .select(['comment.scoreList'])
            .where('comment.relatedType = :relatedType', { relatedType: RelatedType.PROVIDER })
            .andWhere('comment.relatedId = :providerId', { providerId })
            .getMany();

        const labelMap = new Map<string, { total: number; count: number }>();
        for (const row of rows) {
            const scoreList = row.scoreList || [];
            for (const scoreItem of scoreList) {
                if (!scoreItem?.label) {
                    continue;
                }
                const label = scoreItem.label;
                const score = Number(scoreItem.score || 0);
                const current = labelMap.get(label) || { total: 0, count: 0 };
                current.total += score;
                current.count += 1;
                labelMap.set(label, current);
            }
        }

        return Array.from(labelMap.entries()).map(([label, value]) => ({
            label,
            averageScore: value.count ? Number((value.total / value.count).toFixed(1)) : 0,
        }));
    }

    /**
     * 关联评论的用户与服务人员信息
     * @param comments
     */
    private async attachCommentDetails(comments: CommentInfoEntity[]): Promise<CommentWithRelation[]> {
        if (!comments?.length) {
            return [];
        }
        const userIds = Array.from(new Set(comments.map(item => item.userId).filter(Boolean)));
        const providerIds = Array.from(new Set(comments.filter(item => item.relatedType === RelatedType.PROVIDER).map(item => item.relatedId).filter(Boolean)));

        const users = userIds.length
            ? await this.userInfoModel.find({
                where: { id: In(userIds) },
            })
            : [];
        const profiles = providerIds.length
            ? await this.providerProfileModel.find({
                where: { providerId: In(providerIds) },
            })
            : [];

        const userMap = new Map(users.map(user => [user.id, user]));
        const profileMap = new Map(profiles.map(profile => [profile.providerId, profile]));

        return comments.map(comment => {
            const user = userMap.get(comment.userId) || null;
            const relatedEntity = comment.relatedType === RelatedType.PROVIDER ? profileMap.get(comment.relatedId) : null;
            const extendedComment = comment as CommentWithRelation;
            extendedComment.user = user;
            extendedComment.relatedEntity = relatedEntity;
            return extendedComment;
        });
    }

    /**
     * 评论查询
     * @param providerId
     */
    private queryBuilder(providerId: number): SelectQueryBuilder<CommentInfoEntity> {
        return this.commentInfoModel.createQueryBuilder('comment')
            .where('comment.relatedType = :relatedType', { relatedType: RelatedType.PROVIDER })
            .andWhere('comment.relatedId = :providerId', { providerId })
            .orderBy('comment.createTime', 'DESC');
    }
}

